﻿using SocketCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 配置驾驶舱
{
    #region //===枚举===
    public enum eDeviceId : byte
    {
        T72_驾驶仓     = 80,
        T72_战斗仓,
        未指定         = 255
    }
    public enum eFrameType : byte
    {
        LINK_Fr = 0x88, //连接帧
        LINK_AFFIRM_Fr, //连接确认帧
        STATUS_Fr,      //状态帧
        INDICAT_Fr,     //指示帧
        UP_CONFIG_Fr,   //上行硬件配置帧
        DN_CONFIG_Fr,   //下行硬件配置帧
        GET_CONFIG_Fr,  //获得硬件配置命令帧--无参数
        SAVE_CONFIG_Fr,	//保存硬件配置命令帧--无参数
        SET_ANALOG_TAP_Fr,   //设置模拟量和档位量命令帧--参数:analog_tap_pos偏移量
        RESET_Fr,       //复位命令帧--无参数
        CAL_NONL_R_Fr,  //校准非线性帧--参数:cal_pct[]和cal_out的索引,参数1:百分比
    }
    #endregion

    #region //================终端机到上位机通信帧=================
    [StructLayout(LayoutKind.Sequential, Pack = 1), Serializable]
    public struct StatusFrame
    {
        public byte sync;           //同步头0x55
        public byte frame_type;     //帧类型
        public byte device_id;      //设备id码
        public byte analog_code;    //模拟量编码:0--元码,1--规格化后编码---废弃!
        //手动分配内存, 使用时，需要额外对内部数组进行初始化，不然会报错。
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U2)]
        public UInt16[] analogs;    //模拟量:最高位=1--元码, =0--规格化后编码
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] tap_positions; //开关档位--波段开关
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] keys;         //每一位代表一个按键状态:1代表按下,0代表松开
        //public byte check_sum;      //除同步头外其余所有字节和取低8位

        public bool GetSrcCode(int i)
        {
            return analogs[i] >= 0x8000;
        }
        public int GetMax(int i)
        {
            return GetSrcCode(i) ? 16383 : 1000;
        }
        public string analog_str(int i)
        {
            return GetSrcCode(i) ? (analogs[i] & 0x7FFF).ToString() : (analogs[i] / 1000M).ToString("0.0%");
        }
        public bool GetTapPos(int i, int bit)
        {
            return (tap_positions[i] & (1 << bit)) != 0;
        }
        public CheckState GetKey(int i, int bit)
        {
            return (keys[i] & (1 << bit)) != 0 ? CheckState.Indeterminate : CheckState.Unchecked;
        }
    }
    [StructLayout(LayoutKind.Sequential, Pack = 1), Serializable]
    public struct ConfigFrame //len=174B
    {
        public byte sync;           //同步头0x55
        public byte frame_type;     //帧类型
        public byte link_no;        //连接识别码:0(最低层,没有下连信号),1(收到低层信号0之后),2...7;4~7bit=最大连接号,0~3bit=当前连接号
        public byte hw_ver;         //固件版本
        //手动分配内存, 使用时，需要额外对内部数组进行初始化，不然会报错。
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.U1)]
        public byte[] mac;          //MAC地址
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] lip;          //local IP本地IP地址--终端机ip地址
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] sub;          //子网掩码
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] gw;           //网关
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] remote_ip;    //远端IP地址--上位机ip
        public ushort local_port;   //本地端口--终端机端口
        public ushort remote_port;  //远端端口--上位机端口
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] analog_pos;   //采集模拟量占位:-1不采集,0,1...63表示采集的模拟量的存储位置,64,65...127表示采集的值变为开关档位后的存储位置-64
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10, ArraySubType = UnmanagedType.U1)]
        public byte[] key_pos;      //采集开关量的储存位:-1不采集. 低4位表示在keys[]中字节偏移量,高4位表示在字节中的偏移位置
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U1)]
        public byte[] out_pos;   //输出模拟量:-1不使用. 0,1...127使用analogs[]的偏移位置的值输出,,位于out_pos[0](R0)~[4](脉冲),[5](R1),[9](R2)
        //输出开关量:<0不使用. 低3位表示在out[]中字节偏移量,bit4=1表示使能步进电机,高3位表示在字节中的偏移位置.位于out_pos[5]~[14](O0~O9)
        public byte device_id; //设备识别码
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U2)]
        public UInt16[] analog_tap_pos; //模拟量到开关档位量转换值:-1不转换. 0~16383为角度转换单位有效值域
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15, ArraySubType = UnmanagedType.U2)]
        public UInt16[] freq_pwm_max;     //输出脉冲最大频率|输出开关量打开时的pwm值,其中6..9包含4线步进电机驱动电压的pwm值;=0表示电阻输出.
        //public byte check_sum;      //除同步头外其余所有字节和取低8位

        #region //===属性和方法===
        public static int ftOffset => (int)Marshal.OffsetOf<ConfigFrame>("frame_type");
        public static int Get_int(byte[] buf, string name)
        {
            return BitConverter.ToInt32(buf, (int)Marshal.OffsetOf<ConfigFrame>(name));
        }
        #endregion
    }
    #endregion
    #region //================上位机到终端机通信帧=================
    [StructLayout(LayoutKind.Sequential, Pack = 1), Serializable]
    public struct IndicateFrame
    {
        public byte sync;           //同步头0x55
        public byte frame_type;     //帧类型
        public byte device_id;      //设备id码
        public byte analog_code;    //模拟量编码:0--规格化后编码,1--元码
        //手动分配内存, 使用时，需要额外对内部数组进行初始化，不然会报错。
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12, ArraySubType = UnmanagedType.U2)]
        public UInt16[] analogs;    //模拟量
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U1)]
        public byte[] leds;         //每一位代表一个按键状态:1代表按下,0代表松开
        //public byte check_sum;      //除同步头外其余所有字节和取低8位

        public bool src_code => analog_code == 0;
        public int max => src_code ? 100 : 63;
        public bool GetLed(int i, int bit)
        {
            return (leds[i] & (1 << bit)) != 0;
        }
        public void SetLed(int i, int bit, bool var)
        {
            leds[i] = (byte)(var ? (leds[i] | (1 << bit)) : (leds[i] & ~(1 << bit)));
        }
    }
    [StructLayout(LayoutKind.Sequential, Pack = 1), Serializable]
    public struct CommandFrame
    {
        public byte sync;           //同步头0x55
        public byte frame_type;     //帧类型
        public byte link_no;        //连接识别码--目标板终端机编号识别码:0~7
        public byte para;           //携带参数:见帧类型枚举说明
        public ushort para1;          //携带参数:见帧类型枚举说明
        //public byte check_sum;      //除同步头外其余所有字节和取低8位
    }
    #endregion

    public class StatusData : INotifyPropertyChanged
    {
        #region //===字段===
        private StatusFrame statusFrame = new StatusFrame();
        #endregion

        #region //===属性===
        public int 最大值0 => statusFrame.GetMax(0);
        public int 最大值1 => statusFrame.GetMax(1);
        public int 最大值2 => statusFrame.GetMax(2);
        public int 最大值3 => statusFrame.GetMax(3);
        public int 最大值4 => statusFrame.GetMax(4);
        public int 最大值5 => statusFrame.GetMax(5);
        public int 最大值6 => statusFrame.GetMax(6);
        public int 最大值7 => statusFrame.GetMax(7);
        public int 模拟量0 => statusFrame.analogs[0];
        public int 模拟量1 => statusFrame.analogs[1];
        public int 模拟量2 => statusFrame.analogs[2];
        public int 模拟量3 => statusFrame.analogs[3];
        public int 模拟量4 => statusFrame.analogs[4];
        public int 模拟量5 => statusFrame.analogs[5];
        public int 模拟量6 => statusFrame.analogs[6];
        public int 模拟量7 => statusFrame.analogs[7];
        public string 模拟量字符串0 => statusFrame.analog_str(0);
        public string 模拟量字符串1 => statusFrame.analog_str(1);
        public string 模拟量字符串2 => statusFrame.analog_str(2);
        public string 模拟量字符串3 => statusFrame.analog_str(3);
        public string 模拟量字符串4 => statusFrame.analog_str(4);
        public string 模拟量字符串5 => statusFrame.analog_str(5);
        public string 模拟量字符串6 => statusFrame.analog_str(6);
        public string 模拟量字符串7 => statusFrame.analog_str(7);
        public bool TP00 => statusFrame.GetTapPos(0, 0);
        public bool TP01 => statusFrame.GetTapPos(0, 1);
        public bool TP02 => statusFrame.GetTapPos(0, 2);
        public bool TP03 => statusFrame.GetTapPos(0, 3);
        public bool TP04 => statusFrame.GetTapPos(0, 4);
        public bool TP05 => statusFrame.GetTapPos(0, 5);
        public bool TP06 => statusFrame.GetTapPos(0, 6);
        public bool TP07 => statusFrame.GetTapPos(0, 7);
        public bool TP10 => statusFrame.GetTapPos(1, 0);
        public bool TP11 => statusFrame.GetTapPos(1, 1);
        public bool TP12 => statusFrame.GetTapPos(1, 2);
        public bool TP13 => statusFrame.GetTapPos(1, 3);
        public bool TP14 => statusFrame.GetTapPos(1, 4);
        public bool TP15 => statusFrame.GetTapPos(1, 5);
        public bool TP16 => statusFrame.GetTapPos(1, 6);
        public bool TP17 => statusFrame.GetTapPos(1, 7);
        public bool TP20 => statusFrame.GetTapPos(2, 0);
        public bool TP21 => statusFrame.GetTapPos(2, 1);
        public bool TP22 => statusFrame.GetTapPos(2, 2);
        public bool TP23 => statusFrame.GetTapPos(2, 3);
        public bool TP24 => statusFrame.GetTapPos(2, 4);
        public bool TP25 => statusFrame.GetTapPos(2, 5);
        public bool TP26 => statusFrame.GetTapPos(2, 6);
        public bool TP27 => statusFrame.GetTapPos(2, 7);
        public bool TP30 => statusFrame.GetTapPos(3, 0);
        public bool TP31 => statusFrame.GetTapPos(3, 1);
        public bool TP32 => statusFrame.GetTapPos(3, 2);
        public bool TP33 => statusFrame.GetTapPos(3, 3);
        public bool TP34 => statusFrame.GetTapPos(3, 4);
        public bool TP35 => statusFrame.GetTapPos(3, 5);
        public bool TP36 => statusFrame.GetTapPos(3, 6);
        public bool TP37 => statusFrame.GetTapPos(3, 7);
        public CheckState K00 => statusFrame.GetKey(0, 0);
        public CheckState K01 => statusFrame.GetKey(0, 1);
        public CheckState K02 => statusFrame.GetKey(0, 2);
        public CheckState K03 => statusFrame.GetKey(0, 3);
        public CheckState K04 => statusFrame.GetKey(0, 4);
        public CheckState K05 => statusFrame.GetKey(0, 5);
        public CheckState K06 => statusFrame.GetKey(0, 6);
        public CheckState K07 => statusFrame.GetKey(0, 7);
        public CheckState K10 => statusFrame.GetKey(1, 0);
        public CheckState K11 => statusFrame.GetKey(1, 1);
        public CheckState K12 => statusFrame.GetKey(1, 2);
        public CheckState K13 => statusFrame.GetKey(1, 3);
        public CheckState K14 => statusFrame.GetKey(1, 4);
        public CheckState K15 => statusFrame.GetKey(1, 5);
        public CheckState K16 => statusFrame.GetKey(1, 6);
        public CheckState K17 => statusFrame.GetKey(1, 7);
        public CheckState K20 => statusFrame.GetKey(2, 0);
        public CheckState K21 => statusFrame.GetKey(2, 1);
        public CheckState K22 => statusFrame.GetKey(2, 2);
        public CheckState K23 => statusFrame.GetKey(2, 3);
        public CheckState K24 => statusFrame.GetKey(2, 4);
        public CheckState K25 => statusFrame.GetKey(2, 5);
        public CheckState K26 => statusFrame.GetKey(2, 6);
        public CheckState K27 => statusFrame.GetKey(2, 7);
        public CheckState K30 => statusFrame.GetKey(3, 0);
        public CheckState K31 => statusFrame.GetKey(3, 1);
        public CheckState K32 => statusFrame.GetKey(3, 2);
        public CheckState K33 => statusFrame.GetKey(3, 3);
        public CheckState K34 => statusFrame.GetKey(3, 4);
        public CheckState K35 => statusFrame.GetKey(3, 5);
        public CheckState K36 => statusFrame.GetKey(3, 6);
        public CheckState K37 => statusFrame.GetKey(3, 7);
        #endregion


        #region //===事件===
        public event PropertyChangedEventHandler PropertyChanged;//接口自带，用户不用实现方法
        public void Refresh()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("最大值"));
        }
        #endregion

        #region //===方法===
        public StatusData()
        {
            statusFrame.analogs = new UInt16[8];
            for (int i = 0; i < 8; i++)
            {
                statusFrame.analogs[i] = (UInt16)((i * 1000 / 10)/* | 0x8000*/);
            }
            statusFrame.tap_positions = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                statusFrame.tap_positions[i] = (byte)(2 << i);
            }
            statusFrame.keys = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                statusFrame.keys[i] = (byte)(0x55 + i * 2);
            }
        }
        public void Update(byte[] buf)
        {
            statusFrame = (StatusFrame)SocketCom.BytesToStruct(buf, statusFrame.GetType(), 0);
            Refresh();
        }
        #endregion
    }
    public class IndicateData : INotifyPropertyChanged
    {
        #region //===字段===
        private IndicateFrame indicateFrame = new IndicateFrame();
        #endregion

        #region //===属性===
        public byte AnalogCode { get => indicateFrame.analog_code; set => indicateFrame.analog_code = value; }
        public int 最大值 => indicateFrame.max;
        public ushort 模拟量0 { get => indicateFrame.analogs[0]; set { indicateFrame.analogs[0] = value; Refresh(); } }
        public ushort 模拟量1 { get => indicateFrame.analogs[1]; set { indicateFrame.analogs[1] = value; Refresh(); } }
        public ushort 模拟量2 { get => indicateFrame.analogs[2]; set { indicateFrame.analogs[2] = value; Refresh(); } }
        public ushort 模拟量3 { get => indicateFrame.analogs[3]; set { indicateFrame.analogs[3] = value; Refresh(); } }
        public ushort 模拟量4 { get => indicateFrame.analogs[4]; set { indicateFrame.analogs[4] = value; Refresh(); } }
        public ushort 模拟量5 { get => indicateFrame.analogs[5]; set { indicateFrame.analogs[5] = value; Refresh(); } }
        public ushort 模拟量6 { get => indicateFrame.analogs[6]; set { indicateFrame.analogs[6] = value; Refresh(); } }
        public ushort 模拟量7 { get => indicateFrame.analogs[7]; set { indicateFrame.analogs[7] = value; Refresh(); } }
        public ushort 模拟量8 { get => indicateFrame.analogs[8]; set { indicateFrame.analogs[8] = value; Refresh(); } }
        public ushort 模拟量9 { get => indicateFrame.analogs[9]; set { indicateFrame.analogs[9] = value; Refresh(); } }
        public ushort 模拟量10 { get => indicateFrame.analogs[10]; set { indicateFrame.analogs[10] = value; Refresh(); } }
        public ushort 模拟量11 { get => indicateFrame.analogs[11]; set { indicateFrame.analogs[11] = value; Refresh(); } }
        public bool L00 { get => indicateFrame.GetLed(0, 0); set => indicateFrame.SetLed(0, 0, value); }
        public bool L01 { get => indicateFrame.GetLed(0, 1); set => indicateFrame.SetLed(0, 1, value); }
        public bool L02 { get => indicateFrame.GetLed(0, 2); set => indicateFrame.SetLed(0, 2, value); }
        public bool L03 { get => indicateFrame.GetLed(0, 3); set => indicateFrame.SetLed(0, 3, value); }
        public bool L04 { get => indicateFrame.GetLed(0, 4); set => indicateFrame.SetLed(0, 4, value); }
        public bool L05 { get => indicateFrame.GetLed(0, 5); set => indicateFrame.SetLed(0, 5, value); }
        public bool L06 { get => indicateFrame.GetLed(0, 6); set => indicateFrame.SetLed(0, 6, value); }
        public bool L07 { get => indicateFrame.GetLed(0, 7); set => indicateFrame.SetLed(0, 7, value); }
        public bool L10 { get => indicateFrame.GetLed(1, 0); set => indicateFrame.SetLed(1, 0, value); }
        public bool L11 { get => indicateFrame.GetLed(1, 1); set => indicateFrame.SetLed(1, 1, value); }
        public bool L12 { get => indicateFrame.GetLed(1, 2); set => indicateFrame.SetLed(1, 2, value); }
        public bool L13 { get => indicateFrame.GetLed(1, 3); set => indicateFrame.SetLed(1, 3, value); }
        public bool L14 { get => indicateFrame.GetLed(1, 4); set => indicateFrame.SetLed(1, 4, value); }
        public bool L15 { get => indicateFrame.GetLed(1, 5); set => indicateFrame.SetLed(1, 5, value); }
        public bool L16 { get => indicateFrame.GetLed(1, 6); set => indicateFrame.SetLed(1, 6, value); }
        public bool L17 { get => indicateFrame.GetLed(1, 7); set => indicateFrame.SetLed(1, 7, value); }
        public bool L20 { get => indicateFrame.GetLed(2, 0); set => indicateFrame.SetLed(2, 0, value); }
        public bool L21 { get => indicateFrame.GetLed(2, 1); set => indicateFrame.SetLed(2, 1, value); }
        public bool L22 { get => indicateFrame.GetLed(2, 2); set => indicateFrame.SetLed(2, 2, value); }
        public bool L23 { get => indicateFrame.GetLed(2, 3); set => indicateFrame.SetLed(2, 3, value); }
        public bool L24 { get => indicateFrame.GetLed(2, 4); set => indicateFrame.SetLed(2, 4, value); }
        public bool L25 { get => indicateFrame.GetLed(2, 5); set => indicateFrame.SetLed(2, 5, value); }
        public bool L26 { get => indicateFrame.GetLed(2, 6); set => indicateFrame.SetLed(2, 6, value); }
        public bool L27 { get => indicateFrame.GetLed(2, 7); set => indicateFrame.SetLed(2, 7, value); }
        public bool L30 { get => indicateFrame.GetLed(3, 0); set => indicateFrame.SetLed(3, 0, value); }
        public bool L31 { get => indicateFrame.GetLed(3, 1); set => indicateFrame.SetLed(3, 1, value); }
        public bool L32 { get => indicateFrame.GetLed(3, 2); set => indicateFrame.SetLed(3, 2, value); }
        public bool L33 { get => indicateFrame.GetLed(3, 3); set => indicateFrame.SetLed(3, 3, value); }
        public bool L34 { get => indicateFrame.GetLed(3, 4); set => indicateFrame.SetLed(3, 4, value); }
        public bool L35 { get => indicateFrame.GetLed(3, 5); set => indicateFrame.SetLed(3, 5, value); }
        public bool L36 { get => indicateFrame.GetLed(3, 6); set => indicateFrame.SetLed(3, 6, value); }
        public bool L37 { get => indicateFrame.GetLed(3, 7); set => indicateFrame.SetLed(3, 7, value); }
        #endregion

        #region //===事件===
        public event PropertyChangedEventHandler PropertyChanged;//接口自带，用户不用实现方法
        public void Refresh()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("模拟量0"));
        }
        #endregion

        #region //===方法===
        public IndicateData()
        {
            indicateFrame.sync = 0x55;
            indicateFrame.frame_type = (byte)eFrameType.INDICAT_Fr;
            indicateFrame.analog_code = 0;
            indicateFrame.analogs = new UInt16[12];
            for (int i = 0; i < 12; i++)
            {
                indicateFrame.analogs[i] = 0;// (UInt16)(i * indicateFrame.max / 12);
            }
            indicateFrame.leds = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                indicateFrame.leds[i] = 0;// (byte)(0x55 + (1 << i));
            }
        }
        public void SetAnalog(byte i, ushort analog)
        {
            indicateFrame.analogs[i] = analog;
            Refresh();
        }
        public IndicateFrame GetIndicateFrame()
        {
            return indicateFrame;
        }
        public IndicateFrame GetIndicateFrame(byte i, ushort analog)
        {
            indicateFrame.analogs[i] = analog;
            return indicateFrame;
        }
        #endregion
    }
    public class ConfigData : INotifyPropertyChanged
    {
        #region //===字段===
        private ConfigFrame configFrame = new ConfigFrame();
        private int _ch = 0;
        private int _k = 0;
        private int _pi = 0;
        private bool[] isDisable = new bool[4];
        private bool[] isAnalog = new bool[4];
        private bool[] isTap = new bool[4];
        private bool[] isPPWM = new bool[15];
        private bool[] isR = new bool[3];
        private bool isStep = false;
        #endregion

        #region //===属性===
        #region //---连接号---
        public int NowLinkNo => (configFrame.link_no >> 4) - (configFrame.link_no & 0x0F);
        public int MaxLinkCount => (configFrame.link_no >> 4) + 1;
        public string 固件版本 => "固件版本:" + (configFrame.hw_ver >> 4) + "." + (configFrame.hw_ver & 0x0F);
        public string 设备名称 { get => Enum.GetName(typeof(eDeviceId), configFrame.device_id);
            set => configFrame.device_id = (byte)Enum.Parse(typeof(eDeviceId),value); }
        #endregion
        #region //---网络---
        public string MAC地址 => "MAC地址: " + configFrame.mac[0].ToString("X2") +"-" + configFrame.mac[1].ToString("X2")+"-" + configFrame.mac[2].ToString("X2")+"-";
        public string MAC2 { get => configFrame.mac[3].ToString("X2"); set => configFrame.mac[3] = Convert.ToByte(value, 16); }
        public string MAC1 { get => configFrame.mac[4].ToString("X2"); set => configFrame.mac[4] = Convert.ToByte(value, 16); }
        public string MAC0 { get => configFrame.mac[5].ToString("X2"); set => configFrame.mac[5] = Convert.ToByte(value, 16); }
        public string 终端IP { get => GetNetAddr(configFrame.lip); set => SetNetAddr(ref configFrame.lip, value); }
        public string 子网掩码 { get => GetNetAddr(configFrame.sub); set => SetNetAddr(ref configFrame.sub, value); }
        public string 网关 { get => GetNetAddr(configFrame.gw); set => SetNetAddr(ref configFrame.gw, value); }
        public string 远端IP { get => GetNetAddr(configFrame.remote_ip); set => SetNetAddr(ref configFrame.remote_ip, value); }
        public ushort 终端端口 { get => configFrame.local_port; set => configFrame.local_port = value; }
        public ushort 远端端口 { get => configFrame.remote_port; set => configFrame.remote_port = value; }
        #endregion
        #region //<<<输入<<<
        /// <summary>
        /// 模拟通道号
        /// </summary>
        public int ch { get => _ch; set { _ch = value; Refresh(); } }
        public bool 不使能 { get => isDisable[ch]; set => SetAnalogDisable(value); }
        public bool 模拟量 { get => isAnalog[ch]; set => SetAnalog(value); }
        public bool 档位开关 { get => isTap[ch]; set => SetTap(value); }
        public bool 使能值域 => !isDisable[ch];
        public string 模拟量档位序号 => 模拟量 ? "模拟序号:" : "档位位号:";
        public int 模拟量序号 { get => configFrame.analog_pos[ch] & 63; set => configFrame.analog_pos[ch] = (byte)(模拟量 ? value : value | 64); }
        public int 档位值域0 { get => configFrame.analog_tap_pos[ch*10+0]; set => configFrame.analog_tap_pos[ch*10+0] = (UInt16)value; }
        public int 档位值域1 { get => configFrame.analog_tap_pos[ch*10+1]; set => configFrame.analog_tap_pos[ch*10+1] = (UInt16)value; }
        public int 档位值域2 { get => configFrame.analog_tap_pos[ch*10+2]; set => configFrame.analog_tap_pos[ch*10+2] = (UInt16)value; }
        public int 档位值域3 { get => configFrame.analog_tap_pos[ch*10+3]; set => configFrame.analog_tap_pos[ch * 10 + 3] = (UInt16)value; }
        public int 档位值域4 { get => configFrame.analog_tap_pos[ch*10+4]; set => configFrame.analog_tap_pos[ch * 10 + 4] = (UInt16)value; }
        public int 档位值域5 { get => configFrame.analog_tap_pos[ch*10+5]; set => configFrame.analog_tap_pos[ch * 10 + 5] = (UInt16)value; }
        public int 档位值域6 { get => configFrame.analog_tap_pos[ch*10+6]; set => configFrame.analog_tap_pos[ch * 10 + 6] = (UInt16)value; }
        public int 档位值域7 { get => configFrame.analog_tap_pos[ch*10+7]; set => configFrame.analog_tap_pos[ch * 10 + 7] = (UInt16)value; }
        public int 档位值域8 { get => configFrame.analog_tap_pos[ch*10+8]; set => configFrame.analog_tap_pos[ch * 10 + 8] = (UInt16)value; }
        public int 档位值域9 { get => configFrame.analog_tap_pos[ch*10+9]; set => configFrame.analog_tap_pos[ch * 10 + 9] = (UInt16)value; }
        public int k { get=>_k; set{ _k = value; Refresh(); } }
        public bool 使能开关通道 { get => (configFrame.key_pos[k] & 0x80) == 0; set => SetKeyCh(value); }
        public int 开关序号 { get => configFrame.key_pos[k] & 0x0F; set => configFrame.key_pos[k] = (byte)((configFrame.key_pos[k] & 0xF0) | value); }
        public int 开关位号 { get => configFrame.key_pos[k] >> 4; set => configFrame.key_pos[k] = (byte)((configFrame.key_pos[k] & 0x0F) | (value << 4)); }
        #endregion
        #region //>>>输出>>>
        /// <summary>
        /// PWM输出通道序号
        /// </summary>
        public int pi { get => _pi; set { _pi = value; Refresh(); } }
        #region //---输出使能---
        public bool 使能脉冲0 { get => isPPWM[0]; set => SetPPWM(0, value); }
        public bool 使能脉冲1 { get => isPPWM[1]; set => SetPPWM(1, value); }
        public bool 使能脉冲2 { get => isPPWM[2]; set => SetPPWM(2, value); }
        public bool 使能脉冲3 { get => isPPWM[3]; set => SetPPWM(3, value); }
        public bool 使能脉冲4 { get => isPPWM[4]; set => SetPPWM(4, value); }
        public bool 使能PWM { get => isPPWM[pi + 5]; set => SetPPWM(pi + 5, value); }
        public bool 使能电阻0 { get => isR[0]; set => SetER(0, value); }
        public bool 使能电阻1 { get => isR[1]; set => SetER(1, value); }
        public bool 使能电阻2 { get => isR[2]; set => SetER(2, value); }
        public bool 使能步进电机 { get => isStep; set => SetStep(value); }
        #endregion
        #region //---输出变量位于---
        public byte 输出模拟序号0 { get => configFrame.out_pos[0]; set => configFrame.out_pos[0] = value; }
        public byte 输出模拟序号1 { get => configFrame.out_pos[1]; set => configFrame.out_pos[1] = value; }
        public byte 输出模拟序号2 { get => configFrame.out_pos[2]; set => configFrame.out_pos[2] = value; }
        public byte 输出模拟序号3 { get => configFrame.out_pos[3]; set => configFrame.out_pos[3] = value; }
        public byte 输出模拟序号4 { get => configFrame.out_pos[4]; set => configFrame.out_pos[4] = value; }
        public byte LED序号 { get => (byte)(configFrame.out_pos[pi + 5] & 0x07); set => SetOutNo(value); }
        public byte LED位号 { get => (byte)(configFrame.out_pos[pi + 5] >> 4); set => SetOutBit(value); }
        public byte 电阻1模拟序号 { get => configFrame.out_pos[5]; set => configFrame.out_pos[5] = value; }
        public byte 电阻2模拟序号 { get => configFrame.out_pos[4 + 5]; set => configFrame.out_pos[4 + 5] = value; }
        #endregion
        #region //---输出最大值---
        public decimal 脉冲最大值0 { get => GetFmaxHz(0); set => SetFmaxHz(0, value); }
        public decimal 脉冲最大值1 { get => GetFmaxHz(1); set => SetFmaxHz(1, value); }
        public decimal 脉冲最大值2 { get => GetFmaxHz(2); set => SetFmaxHz(2, value); }
        public decimal 脉冲最大值3 { get => GetFmaxHz(3); set => SetFmaxHz(3, value); }
        public decimal 脉冲最大值4 { get => GetFmaxHz(4); set => SetFmaxHz(4, value); }
        public ushort PWM最大值 { get => configFrame.freq_pwm_max[pi + 5]; set { configFrame.freq_pwm_max[pi + 5] = value; Refresh(); } }
        #endregion
        #region //---有效标志---
        public bool 脉冲有效 => !使能电阻0;
        public bool PWM有效 => CheckPWMisValid();
        public bool 电阻有效0 => !使能脉冲0 && !使能脉冲1 && !使能脉冲2 && !使能脉冲3 && !使能脉冲4;
        public bool 电阻有效1 => CheckR1isValid();
        public bool 电阻有效2 => CheckR2isValid();
        public bool 步进电机有效 => CheckStepisValid();
        public bool LED序位号有效 => 使能PWM | 使能步进电机;
        #endregion
        #endregion
        #region //---属性函数---
        private decimal GetFmaxHz(int i)
        {
            return configFrame.freq_pwm_max[i] == 0 ? 0 : 10000 / configFrame.freq_pwm_max[i]; //定时器每100us加1=>10000
        }
        private void SetFmaxHz(int i, decimal value)
        {
            configFrame.freq_pwm_max[i] = value == 0 ? (ushort)0 : Convert.ToUInt16(10000 / value); //定时器每100us加1=>10000
        }
        private void SetAnalogDisable(bool value)
        {
            isDisable[ch] = value;
            if (value)
            {
                configFrame.analog_pos[ch] |= 0x80;
                isAnalog[ch] = isTap[ch] = false;
                Refresh();
            }
            else configFrame.analog_pos[ch] &= 0x7F;
        }
        private void SetAnalog(bool value)
        {
            isAnalog[ch] = value;
            if (value)
            {
                configFrame.analog_pos[ch] &= 0x3F;//63
                isDisable[ch]= isTap[ch] = false;
                Refresh();
            }
            else configFrame.analog_pos[ch] |= 0x40; //64
        }
        private void SetTap(bool value)
        {
            isTap[ch] = value;
            if (value)
            {
                configFrame.analog_pos[ch] &= 0x7F; configFrame.analog_pos[ch] |= 0x40;
                isDisable[ch] = isAnalog[ch] = false;
                Refresh();
            }
            else configFrame.analog_pos[ch] &= 0xBF;// ~0x40;
        }
        private void SetKeyCh(bool value)
        {
            if (value) configFrame.key_pos[k] &= 0x7F;
            else configFrame.key_pos[k] |= 0x80;
            Refresh();
        }
        private void SetPPWM(int i, bool value)
        {
            isPPWM[i] = value;
            if (value)
            {
                configFrame.out_pos[i] &= 0x77;
                if (configFrame.freq_pwm_max[i] == 0) configFrame.freq_pwm_max[i] = 1;
                if (i < 5) isR[0] = false;
                else if (i < 9) isR[1] = false;
                else
                {
                    isR[2] = false;
                    if (i >= 11) isStep = false;
                }
            }
            else
            {
                if (i < 5) { if (!isR[0]) configFrame.out_pos[i] |= 0x80; }
                else if (i < 9) { if (!isR[1]) configFrame.out_pos[i] |= 0x80; }
                else
                {
                    if (i < 11) { if (!isR[2]) configFrame.out_pos[i] |= 0x80; }
                    else if (!isR[2] && !isStep) configFrame.out_pos[i] |= 0x80;
                }
            }
            Refresh();
        }
        private void SetER(int n, bool value)
        {
            isR[n] = value;
            if (value)
            {
                switch (n)
                {
                    case 0:
                        for (int i = 0; i < 5; i++)
                        {
                            isPPWM[i] = false;
                        }
                        configFrame.out_pos[0] &= 0x7F;
                        if (configFrame.out_pos[0] > 12) configFrame.out_pos[0] = 0;
                        configFrame.freq_pwm_max[0] = 0; //使能电阻0,脉冲频率最大值为0!
                        break;
                    case 1:
                        for (int i = 5; i < 9; i++)
                        {
                            isPPWM[i] = false;
                        }
                        configFrame.out_pos[5] &= 0x7F;
                        if (configFrame.out_pos[5] > 12) configFrame.out_pos[5] = 0;
                        configFrame.freq_pwm_max[5] = 0; //使能电阻1,PWM最大值为0!
                        break;
                    case 2:
                        for (int i = 9; i < 15; i++)
                        {
                            isPPWM[i] = false;
                        }
                        configFrame.out_pos[9] &= 0x7F;
                        if (configFrame.out_pos[9] > 12) configFrame.out_pos[9] = 0;
                        configFrame.freq_pwm_max[9] = 0; //使能电阻2,PWM最大值为0!
                        isStep = false;
                        break;
                }
            }
            else
            {
                switch (n)
                {
                    case 0:
                        for (int i = 0; i < 5; i++)
                        {
                            if (configFrame.freq_pwm_max[i] == 0) configFrame.freq_pwm_max[i] = 1; //不使能电阻0脉冲值>0
                            if (!isPPWM[i]) configFrame.out_pos[i] |= 0x80;
                        }
                        break;
                    case 1:
                        for (int i = 5; i < 9; i++)
                        {
                            if (configFrame.freq_pwm_max[i] == 0) configFrame.freq_pwm_max[i] = 1; //不使能电阻0脉冲值>0
                            if (!isPPWM[i]) configFrame.out_pos[i] |= 0x80;
                        }
                        break;
                    case 2:
                        for (int i = 9; i < 15; i++)
                        {
                            if (configFrame.freq_pwm_max[i] == 0) configFrame.freq_pwm_max[i] = 1; //不使能电阻0脉冲值>0
                            if (i < 11) { if (!isPPWM[i]) configFrame.out_pos[i] |= 0x80; }
                            else if (!isPPWM[i] && !isStep) configFrame.out_pos[i] |= 0x80;
                        }
                        break;
                }
            }
            Refresh();
        }
        private void SetStep(bool value)
        {
            isStep = value;
            if (value)
            {
                for (int i = 11; i < 15; i++)
                {
                    configFrame.out_pos[i] &= 0x7F;
                    configFrame.out_pos[i] |= 0x08;
                    if (configFrame.freq_pwm_max[i] == 0) configFrame.freq_pwm_max[i] = 1;
                    isPPWM[i] = false;
                    isR[2] = false;
                }
            }
            else
            {
                for (int i = 11; i < 15; i++)
                {
                    configFrame.out_pos[i] &= 0xF7;
                    if (!isPPWM[i] && !isR[2]) configFrame.out_pos[i] |= 0x80;
                }
            }
            Refresh();
        }
        private void SetOutNo(byte no)
        {
            configFrame.out_pos[pi + 5] = (byte)((configFrame.out_pos[pi + 5] & 0x78) | no);
            if ((pi >= 6) && isStep)
            {
                configFrame.out_pos[11] = configFrame.out_pos[12] =
                    configFrame.out_pos[13] = configFrame.out_pos[14] =
                    configFrame.out_pos[pi + 5];
            }
        }
        private void SetOutBit(byte bit)
        {
            configFrame.out_pos[pi + 5] = (byte)((configFrame.out_pos[pi + 5] & 0x0F) | (bit << 4));
            if ((pi >= 6) && isStep)
            {
                configFrame.out_pos[11] = configFrame.out_pos[12] =
                    configFrame.out_pos[13] = configFrame.out_pos[14] =
                    configFrame.out_pos[pi + 5];
            }
        }
        private bool CheckPWMisValid()
        {
            if (pi < 4)
            {
                if (isR[1]) return false;
            }
            else
            {
                if (isR[2]) return false;
                if ((pi >= 6) && isStep) return false;
            }
            return true;
        }
        private bool CheckR1isValid()
        {
            if ((configFrame.out_pos[5] & 0x80) != 0 &&
                (configFrame.out_pos[6] & 0x80) != 0 &&
                (configFrame.out_pos[7] & 0x80) != 0 &&
                (configFrame.out_pos[8] & 0x80) != 0)
                return true;
            else if (isR[1]) return true;
            else return false;
        }
        private bool CheckR2isValid()
        {
            if ((configFrame.out_pos[9] & 0x80) != 0 &&
                (configFrame.out_pos[10] & 0x80) != 0 &&
                (configFrame.out_pos[11] & 0x80) != 0 &&
                (configFrame.out_pos[12] & 0x80) != 0 &&
                (configFrame.out_pos[13] & 0x80) != 0 && 
                (configFrame.out_pos[14] & 0x80) != 0)
                return true;
            else if (isR[2]) return true;
            return false;
        }
        private bool CheckStepisValid()
        {
            if (pi >= 6) //11-5
            {
                if (isR[2]) return false;
                if (isPPWM[11] || isPPWM[12] || isPPWM[13] || isPPWM[14]) return false;
                return true;
            }
            return false;
        }
        private string GetNetAddr(byte[] buf)
        {
            return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3];
        }
        private void SetNetAddr(ref byte[] buf, string str)
        {
            IPAddress ip;
            if (IPAddress.TryParse(str, out ip))
                buf = ip.GetAddressBytes();
            else Refresh(); //不起作用,why???
        }
        #endregion
        #endregion

        #region //===事件===
        public event PropertyChangedEventHandler PropertyChanged;//接口自带，用户不用实现方法
        public void Refresh()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("不使能"));
        }
        #endregion

        #region //===方法===
        public ConfigData()
        {
            configFrame.link_no = (0 << 4) | 0;
            configFrame.mac = new byte[6] { 0x00, 0x08, 0xdc, 0x11, 0x11, 0x01 };
            configFrame.lip = new byte[4] { 192, 168, 1, 100 };
            configFrame.sub = new byte[4] { 255, 255, 255, 255 };
            configFrame.gw = new byte[4] { 192, 168, 1, 1 };
            configFrame.remote_ip = new byte[4] { 192, 168, 1, 255 };
            configFrame.local_port = 9001;
            configFrame.remote_port = 9000;
            configFrame.hw_ver = 0x10;
            configFrame.analog_pos = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                configFrame.analog_pos[i] = 255;
                isDisable[i] = true;
                isAnalog[i] = false;
                isTap[i] = false;
            }
            configFrame.key_pos = new byte[10];
            for (int i = 0; i < 10; i++)
            {
                configFrame.key_pos[i] = 255;
            }
            configFrame.out_pos = new byte[15];
            for (int i = 0; i < 15; i++)
            {
                configFrame.out_pos[i] = 255;
            }
            configFrame.device_id = 0xFF;
            configFrame.analog_tap_pos = new ushort[40];
            for (int i = 0; i < 40; i++)
            {
                configFrame.analog_tap_pos[i] = (UInt16)(1000 + i);
            }
            configFrame.freq_pwm_max = new ushort[15];
            for (int i = 0; i < 15; i++)
            {
                configFrame.freq_pwm_max[i] = (UInt16)(1000 + i);
            }
            UpdateFlag();
        }
        private void UpdateFlag()
        {
            for (int i = 0; i < 15; i++)
            {
                if ((configFrame.out_pos[i] & 0x80) == 0)
                {
                    if (configFrame.freq_pwm_max[i] != 0)
                    {
                        if (i < 5 && isR[0]) { isPPWM[i] = false; continue; }
                        if (i < 9 && isR[1]) { isPPWM[i] = false; continue; }
                        if (isR[2]) { isStep = isPPWM[i] = false; continue; }
                        if (i == 11 && ((configFrame.out_pos[i] & 0x08) != 0))
                        {
                            isStep = true; //使能步进电机
                            isPPWM[i] = false;
                            continue;
                        }
                        if (i > 11 && isStep) isPPWM[i] = false;
                        else isPPWM[i] = true; //使能脉冲或PWM
                    }
                    else
                    { //使能电阻
                        if (i == 0) isR[0] = true;
                        else if (i == 5) isR[1] = true;
                        else if (i == 9) isR[2] = true;
                    }
                }
                else
                {
                    isPPWM[i] = false;
                    if (i == 0) isR[0] = false;
                    else if (i == 5) isR[1] = false;
                    else if (i == 9) isR[2] = false;
                    else if (i == 11) isStep = false;
                }
            }
        }
        public void Update(byte[] buf)
        {
            configFrame = (ConfigFrame)SocketCom.BytesToStruct(buf, configFrame.GetType(), 0);
            UpdateFlag();
            Refresh();
        }
        public ConfigFrame GetConfigFrame()
        {
            configFrame.frame_type = (byte)eFrameType.DN_CONFIG_Fr;
            return configFrame;
        }
        #endregion
    }
}
